﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace M.Comunicate
{
    public class TCPClient
    {
		private bool Reset = false;

		private bool Resetre = false;
		private IPAddress ip;
		private string IPretry;
		private int Portretry;
		
		private object obj1 = new object();

		private Stopwatch timeout = new Stopwatch();

		private Socket socket = null;

		private Thread th_recieve;

		public event EventHandler<byte[]> ReceiveByte;
		public event EventHandler<string> ReceiveString;

		public bool CreateTCP(string IP, int Port, int Timeout = -1)
		{
			try
			{
				Reset = true;
				Resetre = Reset;
				lock (obj1)
				{
					IPretry = IP;
					Portretry = Port;
					if (socket != null)
					{
						try
						{
							socket.Disconnect(reuseSocket: false);
						}
						catch
						{
						}
						socket.Close();
						socket = null;
					}
					Resetre = false;
					Reset = false;
					socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
					ip = IPAddress.Parse(IP.Trim());
					IPEndPoint point = new IPEndPoint(ip, Port);
					if (Timeout != -1)
					{
						timeout.Restart();
					}
					while (true)
					{
						try
						{
							socket.Connect(point);
						}
						catch
						{
							if (Timeout != -1 && timeout.ElapsedMilliseconds > Timeout)
							{
								Reset = true;
							}
							if (Reset)
							{
								return false;
							}
							Thread.Sleep(50);
							continue;
						}
						break;
					}
					th_recieve = new Thread(Recieve);
					th_recieve.IsBackground = true;
					th_recieve.Start();
					return true;
				}
			}
			catch (Exception ex)
			{
				//savelog.SaveLog(ex);
				return false;
			}
		}

		public void Close()
		{
			try
			{
				Reset = true;
				Resetre = Reset;
				socket.Disconnect(reuseSocket: false);
				socket.Close();
				socket.Dispose();
				socket = null;
			}
			catch
			{
			}
		}


		public void Send(string message)
		{
			while (true)
			{
				try
				{
					if (socket != null)
					{
						byte[] buffer = Encoding.Default.GetBytes(message);
						socket.Send(buffer);
					}
					return;
				}
				catch (Exception ex)
				{
					savelog.SaveLog(ex);
					try
					{
						socket.Disconnect(reuseSocket: false);
						socket.Dispose();
						socket.Close();
					}
					catch
					{
					}
					try
					{
						ConnectRetry();
					}
					catch
					{
					}
					Thread.Sleep(100);
				}
			}
		}

		private void Recieve()
		{
			try
			{
				bool first = true;
				byte[] buffer = new byte[65536];
				MemoryStream stream = new MemoryStream();
				try
				{
					while (true)
					{
						int length = 0;
						length = socket.Receive(buffer);
						if (length <= 0)
						{
							break;
						}
						stream.Write(buffer, 0, length);
						if (length < 65536 && first)
						{
							try
							{
								byte[] data2;
								if (stream.Length < 256)
								{
									data2 = new byte[length];
									Array.Copy(buffer, 0, data2, 0, length);
								}
								else
								{
									data2 = stream.GetBuffer();
								}
								this.ReceiveByte?.Invoke(this,data2);
								if (this.ReceiveString != null)
								{
									string result2 = Encoding.Default.GetString(data2, 0, data2.Length).Trim(default(char));
									this.ReceiveString?.Invoke(this,result2);
								}
							}
							catch (Exception ex4)
							{
								savelog.SaveLog(ex4);
							}
							buffer = new byte[65536];
							stream.Dispose();
							stream = new MemoryStream();
						}
						else if (socket.Available == 0)
						{
							Thread.Sleep(10);
							if (socket.Available == 0)
							{
								byte[] data;
								if (stream.Length < 256)
								{
									data = new byte[length];
									Array.Copy(buffer, 0, data, 0, length);
								}
								else
								{
									data = stream.GetBuffer();
								}
                                try
                                {
                                    this.ReceiveByte?.Invoke(this, data);
                                    if (this.ReceiveString != null)
                                    {
                                        string result = Encoding.Default.GetString(data, 0, data.Length).Trim(default(char));
                                        this.ReceiveString?.Invoke(this,result);
                                    }
                                }
                                catch (Exception ex3)
                                {
                                    savelog.SaveLog(ex3);
                                }
                                buffer = new byte[65536];
								stream.Dispose();
								stream = new MemoryStream();
							}
							else
							{
								buffer = new byte[socket.Available];
							}
						}
						else
						{
							buffer = new byte[socket.Available];
						}
					}
					socket.Disconnect(reuseSocket: false);
					socket.Dispose();
					socket.Close();
					throw new Exception("重新连接");
				}
				catch (Exception ex2)
				{
					savelog.SaveLog(ex2);
					try
					{
						socket.Disconnect(reuseSocket: false);
						socket.Dispose();
						socket.Close();
					}
					catch
					{
					}
					try
					{
						ConnectRetry();
					}
					catch
					{
					}
				}
			}
			catch (Exception ex)
			{
				savelog.SaveLog(ex);
			}
		}

		private void ConnectRetry()
		{
			while (true)
			{
				if (Resetre)
				{
					Resetre = false;
					return;
				}
				socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
				ip = IPAddress.Parse(IPretry);
				IPEndPoint point = new IPEndPoint(ip, Portretry);
				try
				{
					socket.Connect(point);
				}
				catch
				{
					if (Resetre)
					{
						Resetre = false;
						return;
					}
					Thread.Sleep(50);
					continue;
				}
				break;
			}
			th_recieve = new Thread(Recieve);
			th_recieve.IsBackground = true;
			th_recieve.Start();
		}

	}
}
